#pragma once
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "../common/Log.hpp"
#include "../common/util.hpp"
using namespace std;

class Runner
{
public:
    Runner() {}
    ~Runner() {}

public:
    //提供设置进程占用资源大小的接口
    static void SetProcLimit(int _cpu_limit, int _mem_limit)
    {
        // 设置CPU时长
        struct rlimit cpu_rlimit;
        cpu_rlimit.rlim_max = RLIM_INFINITY;
        cpu_rlimit.rlim_cur = _cpu_limit;
        setrlimit(RLIMIT_CPU, &cpu_rlimit);

        // 设置内存大小
        struct rlimit mem_rlimit;
        mem_rlimit.rlim_max = RLIM_INFINITY;
        mem_rlimit.rlim_cur = _mem_limit * 1024; //转化成为KB
        setrlimit(RLIMIT_AS, &mem_rlimit);
    }

    static int Run(const string &file_name, int cpu_limit, int mem_limit)
    {
        string _execute = PathUtil::Exe(file_name);
        string _stdin   = PathUtil::Stdin(file_name);
        string _stdout  = PathUtil::Stdout(file_name);
        string _stderr  = PathUtil::Stderr(file_name);

        umask(0);
        int _stdin_fd = open(_stdin.c_str(), O_CREAT|O_RDONLY, 0644);
        int _stdout_fd = open(_stdout.c_str(), O_CREAT|O_WRONLY, 0644);
        int _stderr_fd = open(_stderr.c_str(), O_CREAT|O_WRONLY, 0644);

        if(_stdin_fd < 0 || _stdout_fd < 0 || _stderr_fd < 0)
        {
            lg(Error, "打开标准文件失败");
            return -1; //代表打开文件失败
        }            

        pid_t pid = fork();
        if (pid < 0)
        {
            lg(Error, "创建子进程失败");
            close(_stdin_fd);
            close(_stdout_fd);
            close(_stderr_fd);
            return -2; //代表创建子进程失败
        }
        else if (pid == 0)
        {
            dup2(_stdin_fd, 0);
            dup2(_stdout_fd, 1);
            dup2(_stderr_fd, 2);
            SetProcLimit(cpu_limit, mem_limit);
            execl(_execute.c_str()/*执行谁*/, _execute.c_str()/*如何执行该程序*/, nullptr);
            exit(1);
        }
        else
        {
            close(_stdin_fd);
            close(_stdout_fd);
            close(_stderr_fd);
            int status = 0;
            waitpid(pid, &status, 0);
            // 输出信号信息
            lg(Info, "运行结束，info：%d", (status & 0x7F));
            return status & 0x7F;
        }
    }
};
